package fun.tan90.easy.binlog.manager.handler;

import cn.hutool.core.util.StrUtil;
import fun.tan90.easy.binlog.base.convention.Res;
import fun.tan90.easy.binlog.base.convention.exception.AbstractException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * description
 * company 铁人科技
 *
 * @author 陈浩杰
 * @date 2022/8/17 8:31
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Res<String> maxUploadSizeExceededException(HttpServletRequest request, MaxUploadSizeExceededException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsgAndData("上传文件过大", message);
    }

    @ExceptionHandler(BindException.class)
    public Res<String> bindException(HttpServletRequest request, BindException exception) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream().map(n -> n.getField() + ":" + n.getDefaultMessage()).collect(Collectors.joining(";"));
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsgAndData("参数绑定异常", message);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Res<String> methodArgumentNotValidException(HttpServletRequest request, MethodArgumentNotValidException exception) {
        List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
        String message = fieldErrors.stream().map(n -> n.getField() + ":" + n.getDefaultMessage()).collect(Collectors.joining(";"));
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsgAndData("入参异常", message);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Res<Void> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsg("请求方法【" + request.getMethod() + "】类型错误");
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Res<Void> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpMediaTypeNotSupportedException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsg("MediaType类型【" + exception.getContentType() + "】类型错误");
    }

    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Res<String> sqlIntegrityConstraintViolationException(HttpServletRequest request, SQLIntegrityConstraintViolationException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsgAndData("Duplicate Key", message);
    }

    @ExceptionHandler(NullPointerException.class)
    public Res<String> nullPointerException(HttpServletRequest request, NullPointerException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), exception.getMessage());
        return Res.errorMsgAndData("系统发生空指针异常", message);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public Res<String> illegalArgumentException(HttpServletRequest request, IllegalArgumentException exception) {
        String message = exception.getMessage();
        log.error("[{}] {} {}", request.getMethod(), getUrl(request), message);
        return Res.errorMsgAndData("参数校验异常", message);
    }

    @ExceptionHandler(AbstractException.class)
    public Res<Void> abstractException(HttpServletRequest request, AbstractException ex) {
        if (ex.getCause() != null) {
            log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex, ex.getCause());
            return Res.errorCodeAndMsg(ex.getErrorCode(), ex.getErrorMessage());
        }
        log.error("[{}] {} [ex] {}", request.getMethod(), request.getRequestURL().toString(), ex.toString());
        return Res.errorCodeAndMsg(ex.getErrorCode(), ex.getErrorMessage());
    }

    @ExceptionHandler(Throwable.class)
    public Res<Void> throwable(HttpServletRequest request, Throwable throwable) {
        log.error("[{}] {} ", request.getMethod(), getUrl(request), throwable);
        return Res.errorMsg(StrUtil.format("服务端发生异常，{}", throwable.getMessage()));
    }

    private String getUrl(HttpServletRequest request) {
        if (!StringUtils.hasLength(request.getQueryString())) {
            return request.getRequestURL().toString();
        }
        return request.getRequestURL().toString() + "?" + request.getQueryString();
    }
}
